package cn.zyq.ykb.system.common;

import cn.hutool.core.util.IdUtil;
import cn.zyq.ykb.beans.admin.Admin;
import cn.zyq.ykb.beans.user.User;
import cn.zyq.ykb.service.sys.SysConfigService;
import cn.zyq.ykb.service.user.UserService;
import cn.zyq.ykb.system.config.common.BaseMapper;
import cn.zyq.ykb.system.enums.core.DeletedTypeEnum;
import cn.zyq.ykb.system.enums.core.ResponseCodeEnum;
import cn.zyq.ykb.system.exception.BusinessException;
import cn.zyq.ykb.system.utils.ReflectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import tk.mybatis.mapper.entity.Example;

import javax.persistence.Id;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
public class BaseService {

    @Autowired
    protected UserService userService;

    @Autowired
    protected SysConfigService sysConfigService;
    /**
     * 获取uuid值
     *
     * @return
     */
    protected String uuid() {
        String uuid = IdUtil.fastSimpleUUID();
        return uuid;
    }

    /**
     * 根据serviceID查询其关联对象
     *
     * @param serviceID
     * @param v
     * @param baseMapper
     * @param <V>
     * @return
     */
    protected <V> V getByServiceID(String serviceID, Class<V> v, BaseMapper baseMapper) {
        if (StringUtils.isBlank(serviceID)) {
            throw new BusinessException(ResponseCodeEnum.NULL_VALUE, "参数serviceID不允许为空");
        }
        Example example = new Example(v);
        example.createCriteria().andEqualTo("serviceID", serviceID);
        List<V> list = baseMapper.selectByExample(example);
        if (list.isEmpty()) return null;
        return list.get(0);
    }

    /**
     * 物理删除（慎用）
     *
     * @param id
     * @param baseMapper
     */
    protected void deleteTrue(Integer id, BaseMapper baseMapper) {
        baseMapper.deleteByPrimaryKey(id);
    }

    /**
     * 逻辑删除，将属性deleted置为1
     *
     * @param id
     * @param baseMapper
     */
    protected void deleteLogic(Integer id, BaseMapper baseMapper) {
        this.deleteLogic(id, null, baseMapper);
    }

    protected void undeleteLogic(Integer id, BaseMapper baseMapper) {
        this.undeleteLogic(id, null, baseMapper);
    }

    /**
     * 逻辑删除，将属性deleted置为1
     *
     * @param id
     * @param baseMapper
     */
    protected void deleteLogic(Integer id, Operator operator, BaseMapper baseMapper) {
        this.delete(id, operator, baseMapper, DeletedTypeEnum.DELETED);

    }

    /**
     * 逻辑删除，将属性deleted置为1
     *
     * @param id
     * @param baseMapper
     */
    protected void undeleteLogic(Integer id, Operator operator, BaseMapper baseMapper) {
        this.delete(id, operator, baseMapper, DeletedTypeEnum.NORMAL);
    }

    private void delete(Integer id, Operator operator, BaseMapper baseMapper, DeletedTypeEnum deletedEnum) {
        Object o = baseMapper.selectByPrimaryKey(id);
        if (o == null) {
            log.error("Logic delete object(id = {}), but object is not found!", id);
            throw new BusinessException(ResponseCodeEnum.NULL_VALUE);
        }
        ReflectionUtil.setFieldValue(o, "deleted", deletedEnum.getValue());
        ReflectionUtil.setFieldValue(o, "updateTime", LocalDateTime.now());
        if (operator != null) {
            Field[] declaredFields = operator.getClass().getDeclaredFields();
            for (Field declaredField : declaredFields) {
                boolean annotationPresent = declaredField.isAnnotationPresent(Id.class);
                if (annotationPresent) {
                    String name = declaredField.getName();
                    Object fieldValue = ReflectionUtil.getFieldValue(operator, name);
                    if (fieldValue == null) {
                        fieldValue = 0;
                    }
                    ReflectionUtil.setFieldValue(o, "updateBy", Integer.parseInt(fieldValue.toString()));
                    break;
                }
            }
        }
        baseMapper.updateByPrimaryKeySelective(o);
    }

    /**
     * 创建空白对象
     *
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T extends BaseBean> T getBlankInstance(Class<T> clazz) {
        try {
            T instance = clazz.newInstance();
            return instance;
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 创建查询有效数据对象
     *
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T extends BaseBean> T getInstance(Class<T> clazz) {
        T instance = this.getBlankInstance(clazz);
        instance.setDeleted(DeletedTypeEnum.NORMAL.getValue());
        return instance;
    }

    protected <T extends BaseBean> T getUpdateInstance(Class<T> clazz, Operator operator) {
        T instance = this.getUpdateInstance(clazz);
        Field[] declaredFields = operator.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            boolean annotationPresent = declaredField.isAnnotationPresent(Id.class);
            if (annotationPresent) {
                String name = declaredField.getName();
                Object fieldValue = ReflectionUtil.getFieldValue(operator, name);
                if (fieldValue == null) {
                    fieldValue = 0;
                }
                instance.setUpdateBy(Integer.parseInt(fieldValue.toString()));
                break;
            }
        }
        return instance;
    }

    /**
     * 创建更新对象
     *
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T extends BaseBean> T getUpdateInstance(Class<T> clazz) {
        T instance = this.getBlankInstance(clazz);
        instance.setUpdateTime(LocalDateTime.now());
        return instance;
    }

    protected <T extends BaseBean> T getCreateInstance(Class<T> clazz, Operator operator) {
        T instance = this.getCreateInstance(clazz);
        setOperator(instance, operator);
        instance.setDeleted(DeletedTypeEnum.NORMAL.getValue());
        return instance;
    }

    /**
     * 创建添加对象
     *
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T extends BaseBean> T getCreateInstance(Class<T> clazz) {
        T instance = this.getUpdateInstance(clazz);
        instance.setServiceID(this.uuid());
        instance.setCreateTime(instance.getUpdateTime());
        return instance;
    }

    /**
     * 检测对象逻辑是否存在
     *
     * @param param
     */
    protected void checkLogicExist(BaseBean param) {
        this.checkLogicExist(param, "数据不存在");
    }

    /**
     * 检测对象逻辑是否存在
     *
     * @param param
     */
    protected void checkLogicExist(BaseBean param, String tip) {
        if (param == null) {
            throw new BusinessException(ResponseCodeEnum.NULL_VALUE, tip);
        }
        if (DeletedTypeEnum.DELETED.getValue().equals(param.getDeleted())) {
            throw new BusinessException(ResponseCodeEnum.NULL_VALUE, tip);
        }
    }

    /**
     * 清除敏感字段
     *
     * @param param
     */
    protected void clearSensitiveFieldValue(BaseBean param) {
        this.clearSensitiveFieldValue(param, false);
    }

    protected void clearSensitiveFieldValue(BaseBean param, boolean clearIDFlag) {
        param.setDeleted(null);
        param.setCreateBy(null);
        param.setCreateTime(null);
        param.setUpdateBy(null);
        param.setUpdateTime(null);
        if (clearIDFlag) {
            ReflectionUtil.setFieldValue(param, "id", null);
        }
    }

    /**
     * 清除敏感字段
     *
     * @param list
     */
    protected void clearSensitiveFieldValue(List<? extends BaseBean> list) {
        this.clearSensitiveFieldValue(list, false);
    }

    protected void clearSensitiveFieldValue(List<? extends BaseBean> list, boolean clearIDFlag) {
        for (BaseBean item : list) {
            this.clearSensitiveFieldValue(item, clearIDFlag);
        }
    }

    protected <T extends BaseBean> void setBaseData(T param, User users) {
        LocalDateTime now = LocalDateTime.now();
        param.setServiceID(this.uuid());
        param.setCreateTime(now);
        param.setUpdateTime(now);
        param.setDeleted(DeletedTypeEnum.NORMAL.getValue());
        param.setCreateBy(users.getUserID());
        param.setUpdateBy(users.getUserID());
    }

    protected <T extends BaseBean> void setBaseData(T param, Admin admin) {
        LocalDateTime now = LocalDateTime.now();
        param.setServiceID(this.uuid());
        param.setCreateTime(now);
        param.setUpdateTime(now);
        param.setDeleted(DeletedTypeEnum.NORMAL.getValue());
        param.setCreateBy(admin.getId());
        param.setUpdateBy(admin.getId());
    }

    protected <T extends BaseBean> void setCreateBaseData(T param, Operator operator) {
        LocalDateTime now = LocalDateTime.now();
        param.setServiceID(this.uuid());
        param.setCreateTime(now);
        param.setUpdateTime(now);
        param.setDeleted(DeletedTypeEnum.NORMAL.getValue());
        setOperator(param, operator);
    }

    protected <T extends BaseBean> void setUpdateBaseData(T param, Operator operator) {
        LocalDateTime now = LocalDateTime.now();
        param.setUpdateTime(now);
        setOperator(param, operator);
    }

    private <T extends BaseBean> void setOperator(T param, Operator operator) {
        Field[] declaredFields = operator.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            boolean annotationPresent = declaredField.isAnnotationPresent(Id.class);
            if (annotationPresent) {
                String name = declaredField.getName();
                Object fieldValue = ReflectionUtil.getFieldValue(operator, name);
                if (fieldValue == null) {
                    fieldValue = 0;
                }
                int createBy = Integer.parseInt(fieldValue.toString());
                param.setCreateBy(createBy);
                param.setUpdateBy(createBy);
                break;
            }
        }
    }
}
